package networks.protocol;

import java.util.ArrayList;
import java.util.List;

// 协议格式
//
// 0     1     2     3     4     5
// +-----+-----+-----+-----+-----+
// |        length         | type|
// +-----------+-----+-----+-----+
// |   route   |  id |           |
// +-----------+-----+           +
// |         ... body ...        |
// +-----------------------------+
//
// Header
// length: 消息长度(type + (route + id + body))
// type: 消息类型 msg=1 handshake=2 heartbeat=3
//
// Message
// route: 路由索引
// id: 请求唯一ID
// body: 参数 prototbuf编码
//

/**
 * 消息协议
 */
public class MessageProtocol {
    public static final int HEADER_LENGTH = 3;
    public static final int MSG_ROUTE_LIMIT = 255;

    private List<String> _route = new ArrayList<String>(); // 路由数组

    public MessageProtocol(String[] route) {
        for (int i = 0; i < route.length; i++) {
            _route.add(route[i]);
        }
    }

    public byte[] Encode(String route, Object msg) {
        return Encode(route, 0, msg);
    }

    public byte[] Encode(String route, int id, Object msg) {
        int routeLength = byteLength(route);
        if (routeLength > MSG_ROUTE_LIMIT) {
            System.out.println("Route is too long! -> " + route);
            return null;
        }

        int routeIndex = _route.indexOf(route);
        if (routeIndex == -1) {
            System.out.println("Route is not exists! -> " + route);
            return null;
        }

        byte[] msgBytes = ((com.google.protobuf.Message) msg).toByteArray();
        int length = msgBytes.length + HEADER_LENGTH;

        byte[] bytes = new byte[length];
        int index = 0;
        bytes[index++] = (byte) (routeIndex >> 8 & 0xFF);
        bytes[index++] = (byte) (routeIndex & 0xFF);
        bytes[index++] = (byte) (id & 0xFF);

        while (index < length) {
            bytes[index] = msgBytes[index - HEADER_LENGTH];
            index++;
        }

        return bytes;
    }

    public Message Decode(byte[] buffer) {
        int routeIndex = buffer[0] << 8 | buffer[1];
        byte id = buffer[2];
        String route = _route.get(routeIndex);

        // Decode body
        byte[] body = new byte[buffer.length - HEADER_LENGTH];
        for (int i = 0; i < body.length; i++) {
            body[i] = buffer[i + HEADER_LENGTH];
        }

        // Construct the message
        MessageType messageType = id > 0 ? MessageType.MSG_RESPONSE : MessageType.MSG_PUSH;
        return new Message(messageType, route, id, body);
    }

    private int byteLength(String msg) {
        return msg.getBytes().length;
    }
}
